#ifndef DEF_HEADER
#define DEF_HEADER
#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
#include<algorithm>
#include<iterator>
#include<vector>
#include<unordered_map>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<random>

using namespace std;

/* Main Definitions */
namespace Puza{
  enum ModelType{
	  MODEL_FM,
	  MODEL_COFM_SHARED_FEATURE,
	  MODEL_COFM_SHARED_SPACE,
	  MODEL_COFM_REG,
	  MODEL_ERROR
  };
  
  enum PointLossType{
	  LOSS_SQUARE,
	  LOSS_LOGISTIC,
	  LOSS_HUBER,
	  LOSS_POISSON,
	  LOSS_POINT_ERROR
  };

  enum RankLossType{
	  LOSS_BPR,
	  LOSS_MRC,
	  LOSS_WARP,
	  LOSS_RANK_ERROR
  };

  enum TaskType{
	  TASK_TRAIN,
	  TASK_PREDICT,
	  TASK_TRAIN_VALIDATION,
	  TASK_ERROR
  };

  enum InputFormat{
	  INPUT_FEATURE,
	  INPUT_ERROR
  };
  
  enum ProcessType{
	  PROCESS_POINT,
	  PROCESS_RANK,
	  PROCESS_ERROR
  };

  /* The definition of files */

  typedef struct PuzaRowItemStruct{
	  int feature_id;
	  double feature_value;
  }PuzaRowItem;

  typedef vector<PuzaRowItem> PuzaRowFeatures;

  typedef struct PuzaRowStruct{
	  double response;
	  PuzaRowFeatures features;
  }PuzaRow;

  typedef struct PuzaSessionStruct{
	 vector<PuzaRow> positive_rows;
	 vector<PuzaRow> negative_rows;
  }PuzaSession;

  typedef vector<PuzaSession> PuzaSessionTable;
  typedef vector<PuzaRow> PuzaRowTable;

  /* This class is a Singleton */
  class PuzaDEF{
  public:
    static PuzaDEF* Instance();
    ModelType CURRENT_MODEL_TYPE;
    TaskType CURRENT_TASK_TYPE;
    PointLossType CURRENT_POINT_LOSS;
    RankLossType CURRENT_RANK_LOSS;
    ProcessType TRAIN_TYPE;
    ProcessType TEST_TYPE;
    InputFormat CURRENT_INPUT_FORMAT;
    string TRAIN_FILE_NAME;
    string PREDICT_FILE_NAME;
    string OUTPUT_FILE_NAME;
    int FACTOR;
    int TOTAL_ITER;
    double LEARNING_RATE;
    double REG;
    double INIT_STDEV = 0.1;
    double TRAIN_THRESHOLD = 1.0;
    
    unordered_map<string,int> FEATURE_MAPPING;
    PuzaRowTable INPUT_ROW_TABLE;
    PuzaSessionTable INPUT_SESSION_TABLE;

    mt19937 rn_eng;

  private:
    PuzaDEF();  // private so that it can  not be called                                                                                               
    PuzaDEF(PuzaDEF const&){}; // copy constructor is private
    static PuzaDEF* m_pInstance;
  };
};

#endif
